#include "Common.hpp"
#include "Protocol.hpp"

// ./client_tcp server_ip server_port
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        cout << "Usage:./client_tcp server_ip server_port" << endl;
        return 1;
    }
    string server_ip = argv[1];  // "192.161.1.1"  点分十进制
    uint16_t server_port = stoi(argv[2]);
    int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        cout << "socket create failed" << endl;
        return 2;
    }
    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_port = htons(server_port);
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());

    // connect
    // client 是不需要显示的进行bind的，tcp是面向连接的，connect底层会自动进行bind
    int n = ::connect(sockfd, CONV(&server_addr), sizeof(server_addr));
    if(n < 0)
    {
        cout << "connect failed" << endl;
        return 3;
    }
    string message;  
    while(true)
    {
        int x, y;
        char operation;
        cout << "input x: ";
        cin >> x;
        cout << "input y: ";
        cin >> y;
        cout << "input operation: ";
        cin >> operation;
        Request req(x,y,operation);
        // 1. 序列化
        req.Serialization(message);
        // 2. 添加报头
        Encode(message);
        // 3. 发送至Server
        n = ::send(sockfd, message.c_str(), message.size(), 0);  // 往sockfd的文件中写入message
        if(n > 0)  // 有消息
        {
            char inbuffer[1024];
            int m = ::recv(sockfd, inbuffer, sizeof(inbuffer), 0);  // 将从sockfd文件中读到的消息放入inbuffer
            if(m > 0)  // 读成功
            {
                inbuffer[m] = '\0';
                string package = inbuffer;
                string content;
                // 4. 解码
                Decode(package, &content);
                // 4. 反序列化
                Response resp;
                resp.deserialization(content);
                // 此时resp就是一个结构化的数据
                // 5. 打印
                cout << "The answer is: " << resp.Result() << ", return code is: " << resp.Code() << endl; 
            }
            else break;
        }
        else break;
    }
    ::close(sockfd);
    return 0;
}